package io.oschina.binv.kapp.framework.utils

import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Bitmap
import android.graphics.Matrix
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.support.media.ExifInterface
import io.oschina.binv.kapp.R
import io.oschina.binv.kapp.framework.extend.printOrReport
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import kotlin.properties.Delegates


/**
 * Created by xuybin on 2017/9/1.
 */
class ImageUtils(val context: Context) {
    var bitmap:Bitmap?=null
    var imageOriginal:String by Delegates.notNull()
    fun with(imageOriginal: String):ImageUtils{
        this.imageOriginal=imageOriginal
        return this
    }

    //保持原图长宽比,限制总大小 或 限制总像素大小,二者都给的,则都同时满足才生成,生成缩略图
    fun thumbnail(maxNumOfPixels: Int=-1, minSideLength: Int=-1,bitmapConfig: Bitmap.Config=Bitmap.Config.RGB_565): ImageUtils {
        try {
            val opts = BitmapFactory.Options()
            opts.inJustDecodeBounds = true
            BitmapFactory.decodeFile(imageOriginal, opts)
            opts.inSampleSize = computeSampleSize(opts, minSideLength, maxNumOfPixels)
            //inJustDecodeBounds set to false to load the actual bitmap
            opts.inJustDecodeBounds = false
            //this options allow android to claim the bitmap memory if it runs low on memory
            opts.inPurgeable = true
            //opts.inInputShareable = true
            opts.inPreferredConfig=bitmapConfig
            //opts.inTempStorage = ByteArray(16 * 1024)
            bitmap = BitmapFactory.decodeFile(imageOriginal, opts)
            bitmap=orientation(bitmap!!)
        } catch (ex: Exception) {
            context.printOrReport(ex)
        }
        return this
    }

    //有最小压缩限制,否则直接返回原图
    fun compressToFile(leastCompressKbSize:Int,compressFormat: Bitmap.CompressFormat=Bitmap.CompressFormat.JPEG,quality: Int=60,imageCompress:String?=null):File{
        if(isNeedCompress(imageOriginal,leastCompressKbSize)){
            return this.thumbnail(1920*1080,1080).compressToFile(compressFormat,quality,imageCompress)
        }
        return File(imageOriginal)
    }

    //无最小压缩限制
    fun compressToFile(compressFormat: Bitmap.CompressFormat=Bitmap.CompressFormat.JPEG,quality: Int=60,imageCompress:String?=null):File{
        var out:FileOutputStream?=null
        var newImageCompress:String by Delegates.notNull()
        try {
            if(imageCompress!=null){
                newImageCompress=imageCompress
            }else{
                newImageCompress="${context.externalCacheDir.absolutePath}${File.separator}cmp${File.separator}cmp_${imageOriginal.substringAfterLast(File.separator).substringBeforeLast('.')}.${compressFormat.name.toLowerCase()}"
            }
            val file=File(newImageCompress)
            if(!file.parentFile.exists()) file.parentFile.mkdirs()
            out = FileOutputStream(newImageCompress)
            bitmap?.compress(compressFormat, quality, out)
            try {
                if (bitmap != null && !bitmap!!.isRecycled) {
                    bitmap!!.recycle()
                }
            } catch (_: IOException) {
            }
        }catch (ex:Throwable){
            context.printOrReport(ex)
            //使用临时目录的文件名再试一次
            if(!newImageCompress.startsWith("${context.externalCacheDir.absolutePath}${File.separator}cmp${File.separator}cmp_")){
                return compressToFile(compressFormat,quality)
            }
        }finally {
            try {
                if (out != null) {
                    out.close()
                }
            } catch (ex: IOException) {
                context.printOrReport(ex)
            }
        }
        return File(newImageCompress)
    }

    private fun orientation(oldBitmap: Bitmap):Bitmap?{
        val exif: android.media.ExifInterface
        exif = android.media.ExifInterface(imageOriginal)
        val orientation = exif.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
        val matrix = Matrix()
        when (orientation) {
        //判断是否需要旋转
            ExifInterface.ORIENTATION_ROTATE_270 ->  matrix.postRotate(270f)
            ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f)
            ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f)
            else->matrix.postRotate(0f)
        }
        //这两个bitmap可能为同一个
        return  Bitmap.createBitmap(oldBitmap, 0, 0, bitmap!!.width, bitmap!!.height, matrix, true)
        return null
    }

    //保持原图长宽比,向上取2的指数返回inSampleSize
   private fun computeSampleSize(options: BitmapFactory.Options, minSideLength: Int, maxNumOfPixels: Int): Int {
        val initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels)
        var roundedSize: Int
        if (initialSize <= 8) {
            roundedSize = 1
            while (roundedSize < initialSize) {
                roundedSize = roundedSize shl 1
            }
        } else {
            //向上取2的指数
            roundedSize = (initialSize + 7) / 8 * 8
        }
        return roundedSize
    }

    //保持原图长宽比,返回inSampleSize
    private fun computeInitialSampleSize(options: BitmapFactory.Options, minSideLength: Int, maxNumOfPixels: Int): Int {
        val w = options.outWidth.toDouble()
        val h = options.outHeight.toDouble()
        val lowerBound = if (maxNumOfPixels == -1) 1 else Math.ceil(Math.sqrt(w * h / maxNumOfPixels)).toInt()
        val upperBound = if (minSideLength == -1) 128 else Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength)).toInt()
        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound
        }
        return if (maxNumOfPixels == -1 && minSideLength == -1) {
            1
        } else if (minSideLength == -1) {
            lowerBound
        } else {
            upperBound
        }
    }

    //leastCompressSize 单位kb
    private fun isNeedCompress(path: String,leastCompressKbSize: Int): Boolean {
        if (leastCompressKbSize > 0) {
            val source = File(path)
            if (!source.exists()) {
                return false
            }

            if (source.length() <= leastCompressKbSize shl 10) {
                return false
            }
        }
        return true
    }
}